import java.util.HashMap;
import java.util.Map;

public class AISParser5 {



    // 假设 binaryStr 是由之前的 stringTo168bit() 生成的168位二进制字符串
    public static String binaryToUtf8(String binaryStr) throws IllegalArgumentException {
        // 1. 先转换为原始ASCII字符串（使用之前的方法）
        String asciiStr = binaryToOriginalString(binaryStr);

        // 2. 直接作为ASCII字符串使用（UTF-8兼容ASCII）
        return asciiStr;
    }

    public static String binaryToOriginalString(String binaryStr) throws IllegalArgumentException {
        // 检查长度是否为6的倍数
        if (binaryStr.length() % 6 != 0) {
            throw new IllegalArgumentException("Binary string length must be a multiple of 6");
        }

        StringBuilder originalStr = new StringBuilder();

        // 每6位一组进行转换
        for (int i = 0; i < binaryStr.length(); i += 6) {
            String sixBits = binaryStr.substring(i, i + 6);
            char c = sixBitToAscii(sixBits);
            originalStr.append(c);
        }

        return originalStr.toString();
    }

    public static char sixBitToAscii(String sixBitStr) throws IllegalArgumentException {


        int binaryValue = Integer.parseInt(sixBitStr, 2);

        // 逆向计算原始ASCII码
        int temp = binaryValue;
        if (temp > 0x80) {
            temp -= 0x20;
        } else {
            temp -= 0x28;
        }
        temp -= 0x28;

        return (char) temp;
    }

    public static String asciiTo6bit(int asciiCode) throws IllegalArgumentException {
        // Range checks
        if (asciiCode < 0x30 || asciiCode > 0x77) {
            throw new IllegalArgumentException("Data error: ASCII code " + asciiCode + " out of range");
        }
        if (0x58 <= asciiCode && asciiCode <= 0x59) {
            throw new IllegalArgumentException("Data error: ASCII code " + asciiCode + " in reserved range");
        }

        // Numerical calculation
        int temp = asciiCode + 0x28;
        if (temp > 0x80) {
            temp += 0x20;
        } else {
            temp += 0x28;
        }

        // Extract lower 6 bits
        int binary6bit = temp & 0x3F;

        // Return 6-bit binary string
        return String.format("%6s", Integer.toBinaryString(binary6bit)).replace(' ', '0');
    }

    public static String stringTo168bit(String inputString) throws IllegalArgumentException {

        // Convert each character to 6-bit binary
        StringBuilder combinedBits = new StringBuilder();
        for (char c : inputString.toCharArray()) {
            int asciiCode = (int) c;
            String bit6 = asciiTo6bit(asciiCode);
            combinedBits.append(bit6);
        }

        return combinedBits.toString();
    }

    public static Map<String, Map<String, Object>> parseAisMessage(String binaryMessage) throws IllegalArgumentException {

        Map<String, Map<String, Object>> fields = new HashMap<>();

        // 1. Message ID
        Map<String, Object> messageId = new HashMap<>();
        messageId.put("binary", binaryMessage.substring(0, 6));
        messageId.put("value", Integer.parseInt(binaryMessage.substring(0, 6), 2));
        messageId.put("description", "Message type identifier");
        fields.put("message_id", messageId);

        // 2. Repeat Indicator
        Map<String, Object> repeatIndicator = new HashMap<>();
        repeatIndicator.put("binary", binaryMessage.substring(6, 8));
        repeatIndicator.put("value", Integer.parseInt(binaryMessage.substring(6, 8), 2));
        repeatIndicator.put("description", "Controls message retransmission");
        fields.put("repeat_indicator", repeatIndicator);

        // 3. User ID/MMSI
        Map<String, Object> userId = new HashMap<>();
        userId.put("binary", binaryMessage.substring(8, 38));
        userId.put("value", Integer.parseInt(binaryMessage.substring(8, 38), 2));
        userId.put("description", "MMSI number (ship unique identifier)");
        fields.put("user_id", userId);

        // 4. Navigation status
        Map<String, String> navigationStatusValues = new HashMap<>();
        navigationStatusValues.put("0", "Under way using engine");
        navigationStatusValues.put("1", "At anchor");
        navigationStatusValues.put("2", "Not under command");
        navigationStatusValues.put("3", "Restricted maneuverability");
        navigationStatusValues.put("4", "Constrained by her draught");
        navigationStatusValues.put("5", "Moored");
        navigationStatusValues.put("6", "Aground");
        navigationStatusValues.put("7", "Engaged in fishing");
        navigationStatusValues.put("8", "Under way sailing");
        for (int i = 9; i <= 15; i++) {
            navigationStatusValues.put(String.valueOf(i), "Reserved for future use");
        }


        int navStatus = Integer.parseInt(binaryMessage.substring(38, 40), 2);
        Map<String, Object> navigationStatus = new HashMap<>();
        navigationStatus.put("binary", binaryMessage.substring(38, 40));
        navigationStatus.put("value", navStatus);
        navigationStatus.put("description", navigationStatusValues.getOrDefault(String.valueOf(navStatus), "Unknown status"));
        navigationStatus.put("status_text", navigationStatusValues.getOrDefault(String.valueOf(navStatus), "Unknown status"));
        fields.put("navigation_status", navigationStatus);

        // 5.IMO编号
        Map<String, Object> IMO = new HashMap<>();
        IMO.put("binary", binaryMessage.substring(40, 70));
        IMO.put("value", Integer.parseInt(binaryMessage.substring(40, 70), 2));
        IMO.put("description", "IMO number");
        fields.put("IMO", IMO);

        // 6.呼号
        Map<String, Object> callSign = new HashMap<>();
        callSign.put("binary", binaryMessage.substring(70, 112));
        callSign.put("value", DecoderUtils.getStringFromStrBit(binaryMessage.substring(70, 112)));//这里对应pdf中的表每6位找到对应的字母
        callSign.put("description", "callSign number");
        fields.put("callSign", callSign);

        // 6.船名
        /**
         * 010011 S
         * 000011 C
         * 010011 S
         * 000011 C
         * 100000 空格
         * 001100 L
         * 010101 U
         * 000011 C
         * 001011 K
         * 100000
         * 100000
         * 100000
         * 100000
         * 100000
         * 100000
         * 100000100000100000100000100000
         */
        Map<String, Object> shipName = new HashMap<>();
        shipName.put("binary", binaryMessage.substring(112, 232));
        shipName.put("value", DecoderUtils.getStringFromStrBit(binaryMessage.substring(112, 232)));//这里对应pdf中的表每6位找到对应的字母
        shipName.put("description", "shipName name");
        fields.put("shipName", shipName);



        // 6.船及货物类型
        Map<String, Object> shipGoodsType = new HashMap<>();
        shipGoodsType.put("binary", binaryMessage.substring(232, 240));
        shipGoodsType.put("value", Integer.parseInt(binaryMessage.substring(232, 240), 2));
        shipGoodsType.put("description", "shipGoodsType");
        fields.put("shipGoodsType", shipGoodsType);

        // 6.总体尺寸/ 位置参考
        Map<String, Object> shipSize = new HashMap<>();
        shipSize.put("binary", binaryMessage.substring(240, 270));
        shipSize.put("value", Integer.parseInt(binaryMessage.substring(240, 270), 2));
        shipSize.put("description", "shipSize");
        fields.put("shipSize", shipSize);

        Map<String, Object> shipSizeD = new HashMap<>();
        shipSizeD.put("binary", binaryMessage.substring(240, 249));
        shipSizeD.put("value", Integer.parseInt(binaryMessage.substring(240, 249), 2));
        shipSizeD.put("description", "shipSizeD");
        fields.put("shipSizeD", shipSizeD);

        Map<String, Object> shipSizeC = new HashMap<>();
        shipSizeC.put("binary", binaryMessage.substring(249, 258));
        shipSizeC.put("value", Integer.parseInt(binaryMessage.substring(249, 258), 2));
        shipSizeC.put("description", "shipSizeC");
        fields.put("shipSizeC", shipSizeC);

        Map<String, Object> shipSizeB = new HashMap<>();
        shipSizeB.put("binary", binaryMessage.substring(258, 264));
        shipSizeB.put("value", Integer.parseInt(binaryMessage.substring(258, 264), 2));
        shipSizeB.put("description", "shipSizeB");
        fields.put("shipSizeB", shipSizeB);

        Map<String, Object> shipSizeA = new HashMap<>();
        shipSizeA.put("binary", binaryMessage.substring(264, 270));
        shipSizeA.put("value", Integer.parseInt(binaryMessage.substring(264, 270), 2));
        shipSizeA.put("description", "shipSizeA");
        fields.put("shipSizeA", shipSizeA);
        //A+B是长 ，C+D是宽

//        Map<String, Object> shipSizeReal = new HashMap<>();
//        shipSizeReal.put("binary", binaryMessage.substring(261, 270));
//        shipSizeReal.put("value", Integer.parseInt(binaryMessage.substring(261, 270), 2));
//        shipSizeReal.put("description", "shipSizeReal");
//        fields.put("shipSizeReal", shipSizeReal);




        // 6.电子定位装置的类型
        Map<String, Object> locaionType = new HashMap<>();
        locaionType.put("binary", binaryMessage.substring(270, 274));
        locaionType.put("value", Integer.parseInt(binaryMessage.substring(270, 274), 2));
        locaionType.put("description", "locaionType");
        fields.put("locaionType", locaionType);

        // 6.ETA 20 月
        Map<String, Object> eta = new HashMap<>();
        eta.put("binary", binaryMessage.substring(274, 278));
        eta.put("value", Integer.parseInt(binaryMessage.substring(274, 278), 2));
        eta.put("description", "eta");
        fields.put("eta", eta);

        // 6.ETA 20 日
        Map<String, Object> etaDay = new HashMap<>();
        etaDay.put("binary", binaryMessage.substring(278, 283));
        etaDay.put("value", Integer.parseInt(binaryMessage.substring(278, 283), 2));
        etaDay.put("description", "etaDay");
        fields.put("etaDay", etaDay);

        // 6.ETA 20 时
        Map<String, Object> etaHour = new HashMap<>();
        etaHour.put("binary", binaryMessage.substring(283, 288));
        etaHour.put("value", Integer.parseInt(binaryMessage.substring(283, 288), 2));
        etaHour.put("description", "etaHour");
        fields.put("etaHour", etaHour);

        // 6.ETA 20 分
        Map<String, Object> etaMin = new HashMap<>();
        etaMin.put("binary", binaryMessage.substring(288, 294));
        etaMin.put("value", Integer.parseInt(binaryMessage.substring(288, 294), 2));
        etaMin.put("description", "etaMin");
        fields.put("etaMin", etaMin);

        // 目前最大静态吃水
        Map<String, Object> draught = new HashMap<>();
        draught.put("binary", binaryMessage.substring(294, 302));
        draught.put("value", Integer.parseInt(binaryMessage.substring( 294,302), 2));
        draught.put("description", "draught");
        fields.put("draught", draught);

        // 目的地
        Map<String, Object> destination = new HashMap<>();
        destination.put("binary", binaryMessage.substring(302, 422));
        destination.put("value", DecoderUtils.getStringFromStrBit(binaryMessage.substring(302, 422)));//这里对应pdf中的表每6位找到对应的字母
        destination.put("description", "destination");
        fields.put("destination", destination);

        // DTE
        Map<String, Object> dte = new HashMap<>();
        dte.put("binary", binaryMessage.substring(422, 423));
        dte.put("value", Integer.parseInt(binaryMessage.substring( 422,423), 2));
        destination.put("description", "dte");
        fields.put("dte", dte);






        //====== end

//        // 6. Speed over ground (SOG)
//        int sogValue = Integer.parseInt(binaryMessage.substring(50, 60), 2);
//        String sogDescription;
//        if (sogValue == 1023) {
//            sogDescription = "No data";
//        } else if (sogValue == 1022) {
//            sogDescription = "102.2 knots or higher";
//        } else {
//            sogDescription = "Speed over ground: " + (sogValue / 10.0) + " knots";
//        }
//        Map<String, Object> speedOverGround = new HashMap<>();
//        speedOverGround.put("binary", binaryMessage.substring(50, 60));
//        speedOverGround.put("value", sogValue);
//        speedOverGround.put("description", sogDescription);
//        fields.put("speed_over_ground", speedOverGround);
//
//        // 7. Position accuracy
//        int posAcc = Integer.parseInt(binaryMessage.substring(60, 61), 2);
//        Map<String, Object> positionAccuracy = new HashMap<>();
//        positionAccuracy.put("binary", binaryMessage.substring(60, 61));
//        positionAccuracy.put("value", posAcc);
//        positionAccuracy.put("description", posAcc == 1 ? "High accuracy (differential)" : "Low accuracy");
//        fields.put("position_accuracy", positionAccuracy);
//
//        // 8. Longitude
//        String lonBits = binaryMessage.substring(61, 89);
//        int lonValue = Integer.parseInt(lonBits, 2);
//        if (lonValue >= (1 << 27)) {
//            lonValue = lonValue - (1 << 28);
//        }
//        double longitude = lonValue / 600000.0;
//        Map<String, Object> longitudeField = new HashMap<>();
//        longitudeField.put("binary", lonBits);
//        longitudeField.put("value", lonValue);
//        longitudeField.put("description", "Ship longitude coordinate: " + longitude + "° " + (longitude >= 0 ? "East" : "West"));
//        fields.put("longitude", longitudeField);
//
//        // 9. Latitude
//        String latBits = binaryMessage.substring(89, 116);
//        int latValue = Integer.parseInt(latBits, 2);
//        if (latValue >= (1 << 26)) {
//            latValue = latValue - (1 << 27);
//        }
//        double latitude = latValue / 600000.0;
//        Map<String, Object> latitudeField = new HashMap<>();
//        latitudeField.put("binary", latBits);
//        latitudeField.put("value", latValue);
//        latitudeField.put("description", "Ship latitude coordinate: " + latitude + "° " + (latitude >= 0 ? "North" : "South"));
//        fields.put("latitude", latitudeField);
//
//        // 10. Course over ground (COG)
//        int cogValue = Integer.parseInt(binaryMessage.substring(116, 128), 2);
//        String cogDescription;
//        if (cogValue == 3600) {
//            cogDescription = "Not available";
//        } else {
//            cogDescription = "Course over ground: " + (cogValue / 10.0) + "°";
//        }
//        Map<String, Object> courseOverGround = new HashMap<>();
//        courseOverGround.put("binary", binaryMessage.substring(116, 128));
//        courseOverGround.put("value", cogValue);
//        courseOverGround.put("description", cogDescription);
//        fields.put("course_over_ground", courseOverGround);
//
//        // 11. True heading
//        Map<String, Object> trueHeading = new HashMap<>();
//        trueHeading.put("binary", binaryMessage.substring(128, 137));
//        trueHeading.put("value", Integer.parseInt(binaryMessage.substring(128, 137), 2));
//        trueHeading.put("description", "Actual heading angle: " + Integer.parseInt(binaryMessage.substring(128, 137), 2) + "°");
//        fields.put("true_heading", trueHeading);
//
//        // 12. Time stamp
//        Map<String, Object> timeStamp = new HashMap<>();
//        timeStamp.put("binary", binaryMessage.substring(137, 143));
//        timeStamp.put("value", Integer.parseInt(binaryMessage.substring(137, 143), 2));
//        timeStamp.put("description", "Time-related marker");
//        fields.put("time_stamp", timeStamp);
//
//        // 13. Regional Application
//        Map<String, Object> regionalApplication = new HashMap<>();
//        regionalApplication.put("binary", binaryMessage.substring(143, 147));
//        regionalApplication.put("value", Integer.parseInt(binaryMessage.substring(143, 147), 2));
//        regionalApplication.put("description", "Reserved for specific regional applications");
//        fields.put("regional_application", regionalApplication);
//
//        // 14. Spare
//        Map<String, Object> spare = new HashMap<>();
//        spare.put("binary", binaryMessage.substring(147, 148));
//        spare.put("value", Integer.parseInt(binaryMessage.substring(147, 148), 2));
//        spare.put("description", "Reserved field");
//        fields.put("spare", spare);
//
//        // 15. RAIM Flag
//        Map<String, Object> raimFlag = new HashMap<>();
//        raimFlag.put("binary", binaryMessage.substring(148, 149));
//        raimFlag.put("value", Integer.parseInt(binaryMessage.substring(148, 149), 2));
//        raimFlag.put("description", "Receiver Autonomous Integrity Monitoring flag");
//        fields.put("raim_flag", raimFlag);
//
//        // 16. Communication state
//        Map<String, Object> communicationState = new HashMap<>();
//        communicationState.put("binary", binaryMessage.substring(149, 168));
//        communicationState.put("value", Integer.parseInt(binaryMessage.substring(149, 168), 2));
//        communicationState.put("description", "Ship communication state related information");
//        fields.put("communication_state", communicationState);

        return fields;
    }

    public static void printAisFields(Map<String, Map<String, Object>> fields) {
        System.out.println("AIS Message Parsing Results:");
        for (Map.Entry<String, Map<String, Object>> entry : fields.entrySet()) {
            String fieldName = entry.getKey();
            Map<String, Object> data = entry.getValue();

            // Convert snake_case to Title Case
            String[] words = fieldName.split("_");
            StringBuilder titleCase = new StringBuilder();
            for (String word : words) {
                titleCase.append(Character.toUpperCase(word.charAt(0)))
                        .append(word.substring(1))
                        .append(" ");
            }

            System.out.println("\n" + titleCase.toString().trim() + ":");
            System.out.println("  Binary: " + data.get("binary"));
            System.out.println("  Value: " + data.get("value"));
            System.out.println("  Description: " + data.get("description"));
        }
    }

    public static void main(String[] args) {
        String testString = "56:;0c4000008uLkR21LDV21TF0IF1<PDpN22216?HJ;;62cjF4j0CQj0BH888888888881";

        try {
            // Convert string to 168-bit binary
            String binaryMessage = stringTo168bit(testString);
            System.out.println("Input string: " + testString);
            System.out.println("Converted 168-bit binary: " + binaryMessage);
            System.out.println("Binary length: " + binaryMessage.length());

            // Parse AIS message
            Map<String, Map<String, Object>> aisFields = parseAisMessage(binaryMessage);

            // Print parsing results
            printAisFields(aisFields);

        } catch (IllegalArgumentException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }


    public static String binaryStringToOriginal(String binaryStr) throws IllegalArgumentException {
        try{
            // 检查输入是否为有效的二进制字符串且长度是6的倍数
            if (binaryStr == null || binaryStr.isEmpty() || !binaryStr.matches("[01]+")) {
                throw new IllegalArgumentException("Input must be a non-empty binary string");
            }
            if (binaryStr.length() % 6 != 0) {
                throw new IllegalArgumentException("Binary string length must be a multiple of 6");
            }

            StringBuilder result = new StringBuilder();
            int length = binaryStr.length();

            // 每6位一组处理
            for (int i = 0; i < length; i += 6) {
                String bit6 = binaryStr.substring(i, Math.min(i + 6, length));
                char c = sixBitToAscii(bit6);
                result.append(c);
            }
            return result.toString();
        }catch (Exception e){
            e.printStackTrace();
        }
        return "-1";


    }

    public static char bit6ToAscii(String bit6) throws IllegalArgumentException {
        // 检查是否为6位二进制字符串
        if (bit6.length() != 6 || !bit6.matches("[01]{6}")) {
            throw new IllegalArgumentException("Input must be a 6-bit binary string");
        }

        // 将二进制字符串转换为整数
        int binary6bit = Integer.parseInt(bit6, 2);

        // 反向计算原始ASCII码
        int temp = binary6bit;

        // 反向处理原始转换逻辑
        if (temp > 0xA0) {
            temp -= 0x20;
        } else {
            temp -= 0x28;
        }

        temp -= 0x28;

        // 范围检查
        if (temp < 0x30 || temp > 0x77) {
            throw new IllegalArgumentException("Decoded ASCII code " + temp + " out of range");
        }
        if (temp >= 0x58 && temp <= 0x59) {
            throw new IllegalArgumentException("Decoded ASCII code " + temp + " in reserved range");
        }

        return (char) temp;
    }


}